package com.solweaver.greetings.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.solweaver.greetings.dao.CountryDAO;
import com.solweaver.greetings.dao.EventDAO;
import com.solweaver.greetings.dao.InviteeDAO;
import com.solweaver.greetings.dao.UserDAO;
import com.solweaver.greetings.dao.UserEventDAO;
import com.solweaver.greetings.dto.Action;
import com.solweaver.greetings.dto.EventCreationRequest;
import com.solweaver.greetings.dto.EventCreationResponse;
import com.solweaver.greetings.dto.EventDTO;
import com.solweaver.greetings.dto.EventErrorEnum;
import com.solweaver.greetings.dto.GenericEnum;
import com.solweaver.greetings.dto.GetEventsByUserRequest;
import com.solweaver.greetings.dto.GetEventsByUserResponse;
import com.solweaver.greetings.dto.GetUsersByEventRequest;
import com.solweaver.greetings.dto.GetUsersByEventResponse;
import com.solweaver.greetings.dto.ModifyEventRequest;
import com.solweaver.greetings.dto.ModifyEventResponse;
import com.solweaver.greetings.dto.UserDTO;
import com.solweaver.greetings.dto.UserEventDTO;
import com.solweaver.greetings.dto.VideoRecordingRequest;
import com.solweaver.greetings.dto.VideoRecordingResponse;
import com.solweaver.greetings.entity.Event;
import com.solweaver.greetings.entity.EventStatus;
import com.solweaver.greetings.entity.InviteStatus;
import com.solweaver.greetings.entity.User;
import com.solweaver.greetings.entity.UserEvent;
import com.solweaver.greetings.entity.UserEventType;
import com.solweaver.greetings.entity.UserStatus;
import com.solweaver.greetings.utils.GenericUtils;

@Service
public class EventServiceImpl implements IEventService{

	@Autowired
	private EventDAO eventDAO;
	
	@Autowired
	private InviteeDAO inviteeDAO;
	
	@Autowired
	private UserDAO userDAO;
	
	@Autowired
	private CountryDAO countryDAO;
	
	@Autowired
	private UserEventDAO userEventDAO;
	
	@Override
	@Transactional
	public EventCreationResponse createEvent(
			EventCreationRequest eventCreationRequest) {
		
		EventCreationResponse eventCreationResponse = new EventCreationResponse();
		Event event = GenericUtils.convertToEventEntity(eventCreationRequest);
		
		try{
			User createdByUser = event.getCreatedBy();
			List<UserStatus> userStatusList = new ArrayList<UserStatus>();
			userStatusList.add(UserStatus.Active);
			List<User> createdByUserList = userDAO.findById(createdByUser.getId(), userStatusList);
			if(createdByUserList != null && createdByUserList.size() > 0 ){
				createdByUser = createdByUserList.get(0);
				if(createdByUser != null){
					if(eventCreationRequest.getRecepientCountry() != null){
						event.setRecepientCountry(countryDAO.findByCode(eventCreationRequest.getRecepientCountry()));
					}
					eventDAO.makePersistent(event);
					//Create user event for event creator
					UserEvent createdByUserEvent = new UserEvent();
					createdByUserEvent.setEvent(event);
					createdByUserEvent.setUser(createdByUser);
					createdByUserEvent.setUserEventType(UserEventType.Inviter);
					userEventDAO.makePersistent(createdByUserEvent);
					if(eventCreationRequest.getInviteeList() != null && eventCreationRequest.getInviteeList().size() > 0){
						for(UserDTO userDTO : eventCreationRequest.getInviteeList()){
							User user = null;
							userStatusList.add(UserStatus.InActive);
							List<User> userList = userDAO.findByEmailOrId(userDTO.getUserId(), userDTO.getEmailId(), userStatusList); 
							if(userList != null && userList.size() > 0){
								user = userList.get(0);
							}else{
								if(userDTO.getUserId() == null){
									user = GenericUtils.convertToUserEntity(userDTO);
									user.setUserStatus(UserStatus.InActive);
									userDAO.makePersistent(user);
								}else{
									GenericUtils.buildErrorDetail(eventCreationResponse, EventErrorEnum.INVALID_INVITEE);
									return eventCreationResponse;
								}
							}
							UserEvent userEvent = new UserEvent();
							userEvent.setEvent(event);
							userEvent.setUser(user);
							userEvent.setUserEventType(UserEventType.Invitee);
							userEvent.setInviteStatus(InviteStatus.Pending);
							userEventDAO.makePersistent(userEvent);
						}
					}
					if(eventCreationRequest.getRecipientUser() != null){
						User recipientUser = null;
						List<User> recipientUserList = userDAO.findByEmailOrId(eventCreationRequest.getRecipientUser().getUserId(),
								eventCreationRequest.getRecipientUser().getEmailId(), userStatusList);
						//List<User> recipientUserList = userDAO.findById(eventCreationRequest.getRecipientUser().getUserId(), userStatusList);
						if(recipientUserList != null && recipientUserList.size() > 0 ){
							recipientUser = recipientUserList.get(0);
							UserEvent userEvent = new UserEvent();
							userEvent.setEvent(event);
							userEvent.setUser(recipientUser);
							userEvent.setUserEventType(UserEventType.RECIPIENT);
							userEventDAO.makePersistent(userEvent);
						}
					}
				}else{
					GenericUtils.buildErrorDetail(eventCreationResponse, GenericEnum.INVALID_CREATED_BY_USER);
				}
			}else{
				GenericUtils.buildErrorDetail(eventCreationResponse, GenericEnum.INVALID_CREATED_BY_USER);
			}
			
		}catch(Exception exception){
			exception.printStackTrace();
			GenericUtils.buildErrorDetail(eventCreationResponse, GenericEnum.DB_EXCEPTION);
		}
		eventCreationResponse.setEventId(event.getId());
		GenericUtils.buildErrorDetail(eventCreationResponse, GenericEnum.Success);
		return eventCreationResponse;
	}

	@Override
	@Transactional
	public GetEventsByUserResponse findEventsByUserId(
			GetEventsByUserRequest getEventsByUserRequest) {
		GetEventsByUserResponse getEventsByUserResponse = new GetEventsByUserResponse();
		
		Long userId = getEventsByUserRequest.getUserId();
		List<EventDTO> eventDTOList = null;
		
		List<UserStatus> userStatusList = new ArrayList<UserStatus>();
		userStatusList.add(UserStatus.Active);
		List<User> userList = userDAO.findById(userId, userStatusList);
		if(userList != null && userList.size() > 0){
			User user = userList.get(0);
			
			List<UserEventType> userEventTypeList = getEventsByUserRequest.getUserEventTypeList();

			List<UserEvent> userEventList = userEventDAO.findByUser(user, userEventTypeList);
			
			List<Event> eventList = null;
			
			if(userEventList != null && userEventList.size() > 0){
				eventList = new ArrayList<Event>();
				for(UserEvent userEvent : userEventList){
					eventList.add(userEvent.getEvent());
				}
			}
			
			eventDTOList = GenericUtils.convertToEventDTOList(eventList);
			getEventsByUserResponse.setEventDTOList(eventDTOList);
			GenericUtils.buildErrorDetail(getEventsByUserResponse, GenericEnum.Success);
		}else{
			GenericUtils.buildErrorDetail(getEventsByUserResponse, GenericEnum.INVALID_USER);
		}
		
		return getEventsByUserResponse;
	}

	@Override
	@Transactional
	public VideoRecordingResponse record(
			VideoRecordingRequest videoRecordingRequest) {
		
		VideoRecordingResponse videoRecordingResponse = new VideoRecordingResponse();
		
		UserEvent userEvent = null;
		
		if(videoRecordingRequest.getUserEventId() != null){
			userEvent = userEventDAO.findById(videoRecordingRequest.getUserEventId(), false);
			if(userEvent == null){
				GenericUtils.buildErrorDetail(videoRecordingResponse, EventErrorEnum.INVALID_USER_EVENT_DETAILS);
				return videoRecordingResponse;
			}
		}
		
		if(videoRecordingRequest.getEventId() != null && videoRecordingRequest.getUserId() != null){
			List<UserEvent> userEventList = userEventDAO.findByUserEvent(videoRecordingRequest.getUserId(), videoRecordingRequest.getEventId());
			if(userEventList != null && userEventList.size() > 0){
				userEvent = userEventList.get(0);
			}else{
				GenericUtils.buildErrorDetail(videoRecordingResponse, EventErrorEnum.INVALID_USER_EVENT_DETAILS);
				return videoRecordingResponse;
			}
		}
		
		StringBuffer recordingLink = new StringBuffer();
		recordingLink.append("video/")	;
		recordingLink.append(userEvent.getEvent().getId());
		recordingLink.append("/");
		recordingLink.append(userEvent.getUser().getId());
		recordingLink.append("_");
		recordingLink.append(Calendar.getInstance().getTimeInMillis());
		
		userEvent.setRecordedLink(recordingLink.toString());
		
		userEventDAO.merge(userEvent);
		videoRecordingResponse.setRecordingLink(recordingLink.toString());
		
		GenericUtils.buildErrorDetail(videoRecordingResponse, GenericEnum.Success);
		
		return videoRecordingResponse;
	}

	@Override
	@Transactional
	public GetUsersByEventResponse findUsersByEvent(
			GetUsersByEventRequest getUsersByEventRequest) {
		GetUsersByEventResponse getUsersByEventResponse = new GetUsersByEventResponse();
		
		Long eventId = getUsersByEventRequest.getEventId();
		
		List<Event> eventList = eventDAO.findById(eventId, EventStatus.Active);
		if(eventList != null && eventList.size() > 0){
			Event event = eventList.get(0);
			
			List<UserEventType> userEventTypeList = new ArrayList<UserEventType>();
			userEventTypeList.add(UserEventType.All);

			List<UserEvent> userEventList = userEventDAO.findByEvent(event);
			
			List<UserEventDTO> userEventDTOList = null;
			
			if(userEventList != null && userEventList.size() > 0){
				userEventDTOList = new ArrayList<UserEventDTO>();
				for(UserEvent userEvent : userEventList){
					UserEventDTO userEventDTO = new UserEventDTO();
					User user = userEvent.getUser();
					userEventDTO.setUserDTO(GenericUtils.convertToUserDTO(user));
					userEventDTO.setInviteeLink(userEvent.getInviteeLink());
					userEventDTO.setInviteStatus(userEvent.getInviteStatus());
					userEventDTO.setRecordedLink(userEvent.getRecordedLink());
					userEventDTO.setUserEventId(userEvent.getId());
					userEventDTO.setUserEventType(userEvent.getUserEventType());
					userEventDTOList.add(userEventDTO);
				}
			}
			
			getUsersByEventResponse.setUserDTOList(userEventDTOList);
			GenericUtils.buildErrorDetail(getUsersByEventResponse, GenericEnum.Success);
		}else{
			GenericUtils.buildErrorDetail(getUsersByEventResponse, EventErrorEnum.INVALID_EVENT_ID);
		}
		
		return getUsersByEventResponse;
	}

	@Override
	@Transactional
	public ModifyEventResponse modifyEvent(ModifyEventRequest modifyEventRequest) {
		ModifyEventResponse modifyEventResponse = new ModifyEventResponse();
		
		Long eventId = modifyEventRequest.getEventId();
		
		List<Event> eventList = eventDAO.findById(eventId, EventStatus.Active);
		
		StringBuffer updatedFields = new StringBuffer();
		
		if(eventList != null && eventList.size() > 0){
			Event event = eventList.get(0);

			if(modifyEventRequest.getAction().equals(Action.MODIFY)){
				if(modifyEventRequest.getDescription() != null){
					event.setDescription(modifyEventRequest.getDescription());
					updatedFields.append(":");
					updatedFields.append("description");
				}
				
				if(modifyEventRequest.getEventDate() != null){
					event.setEventDate(modifyEventRequest.getEventDate());
					updatedFields.append(":");
					updatedFields.append("eventDate");
				}
				
				if(modifyEventRequest.getEventLockDate() != null){
					event.setEventLockDate(modifyEventRequest.getEventLockDate());
					updatedFields.append(":");
					updatedFields.append("eventLockDate");
				}
				
				if(modifyEventRequest.getFromMessage() != null){
					event.setFromMessage(modifyEventRequest.getFromMessage());
					updatedFields.append(":");
					updatedFields.append("fromMessage");
				}
				
				/*if(modifyEventRequest.getRecepientCountry() != null){
					event.setRecepientCountry(recepientCountry);
				}*/

				if(modifyEventRequest.getRecipientUser() != null && modifyEventRequest.getRecipientUser().getUserId() != null){
					User recipientUser = null;
					List<UserStatus> userStatusList = new ArrayList<UserStatus>();
					userStatusList.add(UserStatus.Active);
					userStatusList.add(UserStatus.InActive);
					List<User> recipientUserList = userDAO.findById(modifyEventRequest.getRecipientUser().getUserId(), userStatusList);
					if(recipientUserList != null && recipientUserList.size() > 0 ){
						recipientUser = recipientUserList.get(0);
						UserEvent userEvent = new UserEvent();
						userEvent.setEvent(event);
						userEvent.setUser(recipientUser);
						userEvent.setUserEventType(UserEventType.RECIPIENT);
						userEventDAO.makePersistent(userEvent);
					}else{
						GenericUtils.buildErrorDetail(modifyEventResponse, EventErrorEnum.INVALID_RECIPIENT_USER);
						return modifyEventResponse;
					}
					updatedFields.append(":");
					updatedFields.append("recipientUser");
				}
				
				if(modifyEventRequest.getInviteeList() != null && modifyEventRequest.getInviteeList().size() > 0){
					for(UserDTO userDTO : modifyEventRequest.getInviteeList()){
						User user = null;
						List<UserStatus> userStatusList = new ArrayList<UserStatus>();
						userStatusList.add(UserStatus.Active);
						userStatusList.add(UserStatus.InActive);
						List<User> userList = userDAO.findByEmailOrId(userDTO.getUserId(), userDTO.getEmailId(), userStatusList); 
						if(userList != null && userList.size() > 0){
							user = userList.get(0);
						}else{
							if(userDTO.getUserId() == null){
								user = GenericUtils.convertToUserEntity(userDTO);
								user.setUserStatus(UserStatus.InActive);
								userDAO.makePersistent(user);
							}else{
								GenericUtils.buildErrorDetail(modifyEventResponse, EventErrorEnum.INVALID_INVITEE);
								return modifyEventResponse;
							}
						}
						UserEvent userEvent = new UserEvent();
						userEvent.setEvent(event);
						userEvent.setUser(user);
						userEvent.setUserEventType(UserEventType.Invitee);
						userEvent.setInviteStatus(InviteStatus.Pending);
						userEventDAO.makePersistent(userEvent);
					}
					updatedFields.append(":");
					updatedFields.append("inviteeList");
				}
				
				if(modifyEventRequest.getEventStatus() != null){
					event.setEventStatus(modifyEventRequest.getEventStatus());
					updatedFields.append(":");
					updatedFields.append("eventStatus");
				}
				
				updatedFields.append(":");
				modifyEventResponse.setUpdatedFields(updatedFields.toString());
				
			}else if(modifyEventRequest.getAction().equals(Action.DELETE)){
				event.setEventStatus(EventStatus.Deleted);
			}	
			
			eventDAO.merge(event);
		}else{
			GenericUtils.buildErrorDetail(modifyEventResponse, EventErrorEnum.INVALID_EVENT_ID);
		}
		
		return modifyEventResponse;
	}

}
